First test of a binary classification of stork nest images

Analog the TensorFlow Tutorial: https://www.tensorflow.org/tutorials/images/classification

In [1]:
import tensorflow as tf

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Conv2D, Flatten, Dropout, MaxPooling2D
from tensorflow.keras.preprocessing.image import ImageDataGenerator

import os
import numpy as np
import matplotlib.pyplot as plt
In [2]:
! git clone https://github.com/sschmutz/stork-net.git
fatal: destination path 'stork-net' already exists and is not an empty directory.
In [3]:
train_dir = os.path.join("stork-net/images/2019_train", "train")
validation_dir = os.path.join("stork-net/images/2019_train", "validation")
In [4]:
train_stork_dir = os.path.join(train_dir, "stork")  # directory with our training cat pictures
train_no_stork_dir = os.path.join(train_dir, "no_stork")  # directory with our training dog pictures
validation_stork_dir = os.path.join(validation_dir, "stork")  # directory with our validation cat pictures
validation_no_stork_dir = os.path.join(validation_dir, "no_stork")  # directory with our validation dog pictures
In [5]:
num_stork_tr = len(os.listdir(train_stork_dir))
num_no_stork_tr = len(os.listdir(train_no_stork_dir))

num_stork_val = len(os.listdir(validation_stork_dir))
num_no_stork_val = len(os.listdir(validation_no_stork_dir))

total_train = num_stork_tr + num_no_stork_tr
total_val = num_stork_val + num_no_stork_val
In [6]:
batch_size = 60
epochs = 15
IMG_HEIGHT = 480
IMG_WIDTH = 640
In [7]:
train_image_generator = ImageDataGenerator(rescale=1./255) # Generator for our training data
validation_image_generator = ImageDataGenerator(rescale=1./255) # Generator for our validation data
In [8]:
train_data_gen = train_image_generator.flow_from_directory(batch_size=batch_size,
                                                           directory=train_dir,
                                                           shuffle=True,
                                                           target_size=(IMG_HEIGHT, IMG_WIDTH),
                                                           class_mode="binary")
Found 280 images belonging to 2 classes.
In [9]:
val_data_gen = validation_image_generator.flow_from_directory(batch_size=batch_size,
                                                              directory=validation_dir,
                                                              target_size=(IMG_HEIGHT, IMG_WIDTH),
                                                              class_mode="binary")
Found 60 images belonging to 2 classes.
In [10]:
sample_training_images, _ = next(train_data_gen)
sample_validation_images, _ = next(val_data_gen)
In [11]:
# This function will plot images in the form of a grid with 1 row and 5 columns where images are placed in each column.
def plotImages(images_arr):
    fig, axes = plt.subplots(1, 5, figsize=(20,20))
    axes = axes.flatten()
    for img, ax in zip( images_arr, axes):
        ax.imshow(img)
        ax.axis("off")
    plt.tight_layout()
    plt.show()
In [12]:
plotImages(sample_training_images[:5])
In [13]:
model = Sequential([
    Conv2D(16, 3, padding="same", activation="relu", input_shape=(IMG_HEIGHT, IMG_WIDTH ,3)),
    MaxPooling2D(),
    Conv2D(32, 3, padding="same", activation="relu"),
    MaxPooling2D(),
    Conv2D(64, 3, padding="same", activation="relu"),
    MaxPooling2D(),
    Flatten(),
    Dense(512, activation="relu"),
    Dense(1)
])
In [14]:
model.compile(optimizer="adam",
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=["accuracy"])
In [15]:
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 480, 640, 16)      448       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 240, 320, 16)      0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 240, 320, 32)      4640      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 120, 160, 32)      0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 120, 160, 64)      18496     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 60, 80, 64)        0         
_________________________________________________________________
flatten (Flatten)            (None, 307200)            0         
_________________________________________________________________
dense (Dense)                (None, 512)               157286912 
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 513       
=================================================================
Total params: 157,311,009
Trainable params: 157,311,009
Non-trainable params: 0
_________________________________________________________________
In [16]:
history = model.fit(
    train_data_gen,
    steps_per_epoch=total_train // batch_size,
    epochs=epochs,
    validation_data=val_data_gen,
    validation_steps=total_val // batch_size
)
WARNING:tensorflow:sample_weight modes were coerced from
  ...
    to  
  ['...']
WARNING:tensorflow:sample_weight modes were coerced from
  ...
    to  
  ['...']
Train for 4 steps, validate for 1 steps
Epoch 1/15
4/4 [==============================] - 19s 5s/step - loss: 10.7525 - accuracy: 0.4955 - val_loss: 8.1226 - val_accuracy: 0.4000
Epoch 2/15
4/4 [==============================] - 20s 5s/step - loss: 3.4096 - accuracy: 0.4864 - val_loss: 1.3546 - val_accuracy: 0.6000
Epoch 3/15
4/4 [==============================] - 18s 4s/step - loss: 1.0042 - accuracy: 0.5909 - val_loss: 0.5707 - val_accuracy: 0.8500
Epoch 4/15
4/4 [==============================] - 17s 4s/step - loss: 0.6046 - accuracy: 0.5136 - val_loss: 0.5136 - val_accuracy: 0.9000
Epoch 5/15
4/4 [==============================] - 17s 4s/step - loss: 0.4906 - accuracy: 0.8455 - val_loss: 0.4342 - val_accuracy: 0.7500
Epoch 6/15
4/4 [==============================] - 19s 5s/step - loss: 0.3645 - accuracy: 0.8375 - val_loss: 0.3027 - val_accuracy: 0.9333
Epoch 7/15
4/4 [==============================] - 17s 4s/step - loss: 0.2438 - accuracy: 0.9045 - val_loss: 0.2492 - val_accuracy: 0.9167
Epoch 8/15
4/4 [==============================] - 17s 4s/step - loss: 0.1572 - accuracy: 0.9409 - val_loss: 0.1946 - val_accuracy: 0.9167
Epoch 9/15
4/4 [==============================] - 17s 4s/step - loss: 0.1118 - accuracy: 0.9591 - val_loss: 0.2699 - val_accuracy: 0.9167
Epoch 10/15
4/4 [==============================] - 17s 4s/step - loss: 0.1161 - accuracy: 0.9545 - val_loss: 0.1876 - val_accuracy: 0.9167
Epoch 11/15
4/4 [==============================] - 17s 4s/step - loss: 0.0753 - accuracy: 0.9636 - val_loss: 0.1834 - val_accuracy: 0.9167
Epoch 12/15
4/4 [==============================] - 19s 5s/step - loss: 0.0739 - accuracy: 0.9750 - val_loss: 0.2025 - val_accuracy: 0.9333
Epoch 13/15
4/4 [==============================] - 17s 4s/step - loss: 0.0418 - accuracy: 0.9864 - val_loss: 0.1942 - val_accuracy: 0.9000
Epoch 14/15
4/4 [==============================] - 17s 4s/step - loss: 0.0371 - accuracy: 0.9864 - val_loss: 0.1775 - val_accuracy: 0.9333
Epoch 15/15
4/4 [==============================] - 17s 4s/step - loss: 0.0311 - accuracy: 0.9909 - val_loss: 0.1723 - val_accuracy: 0.9000
In [17]:
acc = history.history["accuracy"]
val_acc = history.history["val_accuracy"]

loss=history.history["loss"]
val_loss=history.history["val_loss"]

epochs_range = range(epochs)

plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label="Training Accuracy")
plt.plot(epochs_range, val_acc, label="Validation Accuracy")
plt.legend(loc="lower right")
plt.title("Training and Validation Accuracy")

plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label="Training Loss")
plt.plot(epochs_range, val_loss, label="Validation Loss")
plt.legend(loc="upper right")
plt.title("Training and Validation Loss")
plt.show()
In [18]:
predictions = model.predict(val_data_gen)
In [19]:
predictions
Out[19]:
array([[ 7.2407227 ],
       [-1.034965  ],
       [18.07834   ],
       [-2.4169886 ],
       [-6.6787605 ],
       [-3.5696018 ],
       [ 1.2270204 ],
       [-4.2327933 ],
       [13.981042  ],
       [-0.59164876],
       [-3.5862205 ],
       [ 0.4208827 ],
       [ 9.623508  ],
       [ 9.561688  ],
       [-3.6531367 ],
       [-1.0852063 ],
       [-6.6489677 ],
       [-3.1671016 ],
       [12.440884  ],
       [ 4.3728867 ],
       [-5.4200034 ],
       [ 6.6527176 ],
       [12.128969  ],
       [11.450594  ],
       [-3.9895272 ],
       [-6.6495056 ],
       [13.058618  ],
       [ 8.594401  ],
       [-5.6813936 ],
       [-3.3495984 ],
       [ 1.623178  ],
       [ 9.121863  ],
       [ 4.2288094 ],
       [ 8.409835  ],
       [15.494876  ],
       [-5.4971824 ],
       [ 1.6553261 ],
       [12.117804  ],
       [10.354308  ],
       [11.04592   ],
       [15.557891  ],
       [12.362901  ],
       [ 9.42447   ],
       [16.200724  ],
       [-2.128915  ],
       [ 7.0024023 ],
       [10.395932  ],
       [12.001182  ],
       [13.513967  ],
       [ 9.394168  ],
       [ 9.114196  ],
       [ 0.289784  ],
       [ 7.5440493 ],
       [-4.605207  ],
       [ 3.5573752 ],
       [12.41875   ],
       [-4.463743  ],
       [12.989961  ],
       [ 1.5646665 ],
       [11.837213  ]], dtype=float32)
In [20]:
predictions.shape
Out[20]:
(60, 1)
In [21]:
predictions_prob = tf.round(tf.nn.sigmoid(predictions))
predictions_prob.shape
Out[21]:
TensorShape([60, 1])
In [22]:
fig, axes = plt.subplots(12, 5, figsize=(24, 40))
axes = axes.flatten()
for img, ax, i in zip(sample_validation_images, axes, range(60)):
    ax.imshow(img)
    ax.axis("off")
    ax.set_title(round(predictions.item(i)))
plt.tight_layout()
plt.show()
In [ ]: